#pragma once
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <string>
#include <vector>
#include "Operation.hpp"
#include <sstream>
#include <sys/wait.h>
#include "Log.hpp"
#include <fcntl.h>
#include <unordered_map>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include "Uint.hpp"
#define STEP ": "
#define OK 200
#define NOTFIND 404
#define BAD_REQUESR 400
#define WEB_ROOT "wwwroot"
#define HOME_PAGE "index.html"
#define PAGE_404 "404.html"
#define LINE_END "\r\n"
class HttpRequest
{
public:
    HttpRequest()
    {
        buildSuffix();
    }
    // // {".html", "text/html"},
    //     {".css", "text/css"},
    //     {".js", "application/javascript"},
    //     {".jpg", "application/x-jpg"},
    //     {".xml", "application/xml"},
    void buildSuffix()
    {
        _suffix.insert({".html", "text/html"});
        _suffix.insert({".css", "text/css"});
        _suffix.insert({".js", "application/javascript"});
        _suffix.insert({".jpg", "application/x-jpg"});
        _suffix.insert({".xml", "application/xml"});
    }
    std::string _request_line;                // 请求行
    std::string _request_back;                // 空行
    std::vector<std::string> _request_header; // 报头
    std::string _request_body;                // 正文部分；

    std::string _request_method;
    std::string _request_url;
    std::string _request_version;
    size_t _lenght = 0;
    std::string _path;
    std::string _query_string;
    bool _cgi = false;
    std::unordered_map<std::string, std::string> _suffix;
    std::unordered_map<std::string, std::string> _request_kv; // 存放报头的key vaule结构的；
};

class HttpResponse
{
public:
    std::string _status_line;
    std::string _blank;
    std::vector<std::string> _header;
    std::string _body;
    size_t _size;
    size_t _status_code;
    std::string _type;
    int _fd;
};

// 这个类负责读取请求，分析请求，构建响应；
class EndPoint
{
private:
    bool getHttpRequesLine()
    {
        auto &outline = _request._request_line;
        if (Uint::getHttpLine(_sock, outline) <= 0)
        {
            _stop = true;
            return _stop;
        }
        outline.resize(outline.size() - 1);
        // LOG(INFO,outline);
        // std::cout << outline << std::endl;
        return _stop;
    }
    bool recvHttpRequesHeader()
    {
        // 将报头读进requse._reques_header中
        std::string outline;
        while (true)
        {
            outline.clear(); // 清除残留；
            if (Uint::getHttpLine(_sock, outline) <= 0)
            {
                _stop = true;
                break;
            }
            if (outline == "\n")
            {
                _request._request_back = outline;
                break;
            }
            outline.resize(outline.size() - 1);
            // outline[outline.size() - 1] = 0;
            _request._request_header.push_back(outline);
            // LOG(INFO,outline);
            // std::cout << outline << std::endl;
        }
        return _stop;
    }
    void ParseHttpLine()
    {
        // 分析请求行；
        std::stringstream ss(_request._request_line);
        ss >> _request._request_method >> _request._request_url >> _request._request_version;
        // std::cout << _request._request_method << std::endl;
        // std::cout << _request._request_url << std::endl;
        // std::cout << _request._request_version << std::endl;
        // LOG(INFO,_request._request_method);
        // LOG(INFO,_request._request_url);
        // LOG(INFO,_request._request_version);
    }
    void ParseHttpHeader()
    {
        // 将报头以kv形式呈现；方便后续的查找；
        std::string key, value;
        for (auto &e : _request._request_header)
        {
            if (Uint::cutHttpHeader(e, key, value, STEP))
            {
                _request._request_kv.insert({key, value});
                std::cout << key << " " << value << std::endl;
            }
            else
            {
                break;
            }
        }
    }
    bool isRecvHttpResquestBody()
    {
        if (_request._request_method == "POST")
        {
            // 代表有正文部分；
            // 通过查找kv;
            std::unordered_map<std::string, std::string>::iterator it = _request._request_kv.find("Content-Length");
            if (it != _request._request_kv.end())
            {
                _request._lenght = std::stoi(it->second);
                return true;
            }
        }
        return false;
    }
    bool RecvHttpBody()
    {
        if (isRecvHttpResquestBody())
        {
            char ch;
            int len = _request._lenght;
            auto &body = _request._request_body;
            // 一个一个的读取；
            while (len--)
            {
                recv(_sock, &ch, 1, 0);
                body += ch;
            }
            return true;
        }
        return false;
    }
    int ProcessCGI()
    {
        std::string method = _request._request_method;
        std::string body = _request._request_body;
        std::string query_string = _request._query_string;
        std::string method_env;
        std::string query_env = "QUERY_STRING=";
        std::string content_lenght = "Content-Length=";
        // 走到这里，有参数或者是可执行程序；
        // 以父进程为参考；
        int input[2];
        int output[2];
        if (pipe(input) != 0)
        {
            std::cout << "err" << std::endl;
            return NOTFIND;
        }
        if (pipe(output) != 0)
        {
            std::cout << "err" << std::endl;
            return NOTFIND;
        }
        pid_t pid = fork();
        if (pid == 0)
        {
            close(input[0]);
            close(output[1]);
            // 当程序替换完之后，子进程不知道读写fd；
            dup2(output[0], 0); // 以后往0中读就是读取output中；
            dup2(input[1], 1);
            // 给子进程发送消息也可以通过环境变量；以kv结构呈现的；
            method_env = "METHOD=";
            method_env += method;
            putenv((char *)method_env.c_str());
            if (method == "GET")
            {
                query_env += query_string;
                putenv((char *)query_env.c_str());
            }
            else if (method == "POST")
            {
                content_lenght += std::to_string(_request._request_body.size());
                putenv((char *)content_lenght.c_str());
            }
            execlp(_request._path.c_str(), _request._path.c_str(), nullptr);
            exit(0);
        }
        else if (pid < 0)
        {
            // err
            std::cout << "err" << std::endl;
            return NOTFIND;
        }
        else
        {
            // parent;
            close(input[1]);
            close(output[0]);
            // 给子进程发送数据；
            // 判断是那种方法；
            if (_request._request_method == "POST")
            {
                // 一般传递的数据比较多；
                // 需要分批次的来传递；
                int size = body.size();
                int total = 0;
                while (total < size)
                {
                    int n = write(output[1], body.c_str() + total, size);
                    total += n;
                }
            }

            char ch;
            while (read(input[0], &ch, 1) > 0)
            {
                _response._body.push_back(ch);
            }
            // 读完之后；等待；
            int status;
            pid_t tmp = waitpid(pid, &status, 0);
            close(input[0]);
            close(output[1]);
        }
        return OK;
    }
    int ProcessNotCGI()
    {
        // _response._blank+=LINE_END;
        int fd = open(_request._path.c_str(), O_RDONLY);
        if (fd > 0)
        {
            std::cout<<"fd:"<<fd<<std::endl;
            _response._fd = fd;
            return OK;
        }
        return NOTFIND;
    }
    std::string CodeToDir(int code)
    {
        std::string Code;
        switch (code)
        {
        case 200:
            Code = "OK";
            break;
        case 404:
            Code =  "NOTFIND";
            break;
        }
        return Code;
    }
    void BuildOKResponse()
    {
        std::cout<<"BUidOk"<<std::endl;
        std::string Suffix = "Content-Type: ";
        std::string Length = "Content-Length: ";
        Suffix += _request._suffix.find(_response._type)->second;
        _response._header.push_back(Suffix);
        if (_request._cgi)
        {
            std::cout << _response._body.size() << std::endl;
            Length += std::to_string(_response._body.size());
        }
        else
        {
            Length += std::to_string(_response._size);
        }
        _response._header.push_back(Length);
    }
    void HelperError(std::string page)
    {
        // 构建错误响应;
        _request._cgi = false;
        int fd = open(page.c_str(), O_RDONLY);
        if (fd > 0)
        {
            // 打开成功；
            _response._fd = fd;
            std::cout << "file success" << std::endl;
            struct stat st;
            stat(page.c_str(), &st); // 文件一定存在；
            _response._size = st.st_size;
            std::string line = "Content-Type: text/html";
            std::string length = "Content-Length: ";
            length += std::to_string(_response._size);
            _response._header.push_back(line);
            _response._header.push_back(length);
        }
    }
    void BuildHttpResponseHelper()
    {
        // 统一在这里进行响应行的构建；
        // std::cout << "___________________" << std::endl;
        std::string &line = _response._status_line;
        line = _request._request_version;
        line += " ";
        line += std::to_string(_response._status_code);
        line += " ";
        line += CodeToDir(_response._status_code);
        line += LINE_END;
        std::string path = WEB_ROOT;
        path += "/";
        // std::cout << _response._status_code << std::endl;
        switch (_response._status_code)
        {
        case 200: // ok
            BuildOKResponse();
            break;
        case 404: // NOTFIND
            path += PAGE_404;
            HelperError(path);
            break;
        case 400:
            break;
        }
    }

public:
    void recvHttpRequest()
    {
        if (!getHttpRequesLine() && !recvHttpRequesHeader())
        {
            ParseHttpLine();
            ParseHttpHeader();
            RecvHttpBody();
        }

        // Debug();
    }
    void buildHttpResponse()
    {
        std::string tmp_path;
        size_t pos;
        struct stat file_state;
        size_t found;
        std::string &type = _response._type;
        if (_request._request_method != "GET" && _request._request_method != "POST")
        {
            // 非正常请求；
            _response._status_code = BAD_REQUESR;
            goto END;
        }
        if (_request._request_method == "GET")
        {
            // 有两种情况，1：没有参数，2：有参数；
            pos = _request._request_url.find("?");
            if (pos != std::string::npos)
            {
                // 说明带参；
                Uint::cutHttpHeader(_request._request_url, _request._path, _request._query_string, "?");
                // std::cout << "++++++++++++++++++" << std::endl;
                std::cout << _request._request_url << std::endl;
                std::cout << _request._path << std::endl;
                std::cout << _request._query_string << std::endl;
                _request._cgi = true;
            }
            else
            {
                // std::cout << _request._request_url << std::endl;
                _request._path = _request._request_url;
            }
        }
        else if (_request._request_method == "POST")
        {
            // 如果是POST，一定带参，参数位于正文部分；
            _request._path = _request._request_url;
            _request._cgi = true;
        }
        else
        {
            // 一定出错了；
            _response._status_code = BAD_REQUESR;
            goto END;
        }

        // 组装访问路径；
        tmp_path = _request._path;
        _request._path = WEB_ROOT;
        _request._path += tmp_path;
        if (_request._path[_request._path.size() - 1] == '/')
        {
            // 说明这是一个默认WEB根目录；
            _request._path += HOME_PAGE;
            std::cout << _request._path << std::endl;
        }
        // 判断是否为合法的资源文件；
        if (stat(_request._path.c_str(), &file_state) == 0)
        {
            // 表示资源存在；
            // 可能是文件，也可能是可执行程序；
            std::cout << "file excit" << std::endl;
            if (S_ISDIR(file_state.st_mode))
            {
                // 是目录；
                // 每一个目录下面多有一个默认文件；
                _request._path += '/';
                _request._path += HOME_PAGE;
                stat(_request._path.c_str(), &file_state); // 更新文件的属性；
            }
            if (file_state.st_mode & S_IXUSR || file_state.st_mode & S_IXGRP || file_state.st_mode & S_IXOTH)
            {
                // 是可执行程序，后面再写；
                _request._cgi = true;
            }
            _response._size = file_state.st_size;
            _response._status_code = OK;
        }
        else
        {
            // not find file;
            _response._status_code = NOTFIND;
            std::cout << "not file" << std::endl;
            goto END;
        }
        found = _request._path.rfind('.');
        if (found != std::string::npos)
        {
            type = _request._path.substr(found);
        }
        else
        {
            type = ".html";
        }
        // Suffix += _request._suffix.find(type)->second;
        // _response._header.push_back(Suffix);
        // Length += std::to_string(_response._size);
        // _response._header.push_back(Length);
        // 分情况，如果是GET就传递query_string
        if (_request._cgi)
        {
            std::cout << "cig" << std::endl;
            _response._status_code = ProcessCGI();
        }
        else
        {
            std::cout << "not cig" << std::endl;
            _response._status_code = ProcessNotCGI();
        }
    END:
        // std::cout << "ddddddd" << std::endl;
        BuildHttpResponseHelper();
    }
    void SendHttpResponse()
    {
        // 发送状态行
        std::cout<<"请求行发送成功"<<std::endl;
        send(_sock, _response._status_line.c_str(), _response._status_line.size(), 0);
        std::cout<<"请求行发送成功"<<std::endl;
        // 发送头部字段
        for (auto &e : _response._header)
        {
            send(_sock, e.c_str(), e.size(), 0);
            send(_sock, "\r\n", 2, 0); // 每个头部字段以 \r\n 结尾
        }
        std::cout<<"报头发送成功"<<std::endl;

        // 发送空行（分隔头部和正文）
        send(_sock, "\r\n", 2, 0);

        // 发送正文
        if (_request._cgi)
        {
            // 没有打开文件；发送body；
            std::cout << _response._body << std::endl;
            size_t size = _response._body.size();
            size_t total;
            while (total < size)
            {
                int n = write(_sock, _response._body.c_str() + total, size - total);
                total += n;
            }
        }
        else
        {
            int n = sendfile(_sock, _response._fd, nullptr, _response._size);
            std::cout << _response._size << std::endl;
            if (n > 0)
            {
                std::cout << "success" << std::endl;
            }
        }
        std::cout<<"正文发送成功"<<std::endl;
        // 关闭文件描述符
        close(_response._fd);
    }
    EndPoint(int sock) : _sock(sock)
    {
    }
    ~EndPoint()
    {
        close(_sock);
    }
    bool IsStop()
    {
        return _stop;
    }
private:
    HttpRequest _request;
    HttpResponse _response;
    int _sock;
    bool _stop = false;
};
